package top.zhimingw.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import top.zhimingw.pojo.*;
import top.zhimingw.redis.ArchivesKey;
import top.zhimingw.redis.ArticleKey;
import top.zhimingw.service.ArticleService;
import top.zhimingw.service.BaseService;
import top.zhimingw.utils.ImageUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author:zhimingw
 * @Version 1.0
 * @since 2021/5/30 21:03
 */
@Service("articleService")
public class ArticleServiceImpl extends BaseService implements ArticleService {

    /**
    * @Description: 添加Article
    * @Param: [article]
    * @return: boolean
    * @Author: zhimingw
    * @Date: 2021/5/31
    */
    @Override
    public boolean insert(Article article) {
        if(articleMapper.insert(article)==1){
            return true;
        }
        return false;
    }

    /**
    * @Description: 删除Article
    * @Param: [id]
    * @return: boolean
    * @Author: zhimingw
    * @Date: 2021/5/31
    */
    @Override
    public boolean deleteById(Integer id) {
        if(articleMapper.deleteById(id)==1){
            return true;
        }
        return false;
    }

    /**
    * @Description: 查询单条数据
    * @Param: [id]
    * @return: top.zhimingw.pojo.Article
    * @Author: zhimingw
    * @Date: 2021/5/31
    */
    @Override
    public Article queryById(Integer id) {
        Article article = null;
        if(redisService.exists(ArticleKey.getById,String.valueOf(id))){
            article = redisService.get(ArticleKey.getById, String.valueOf(id), Article.class);
        }else{
            article = articleMapper.queryById(id);
            if(article==null){
                return article;
            }
            //获取文章的分类
            Kind kinds = articleKindMapper.queryByArticleId(id);
            //获取该文字的标签
            List<Tag> tags = articleTagMapper.queryByArticleId(id);
            article.setKinds(kinds);
            article.setTags(tags);
            if(!ObjectUtils.isEmpty(article)){
                redisService.set(ArticleKey.getById,String.valueOf(id),article,60*60*24);
            }
        }
        return article;
    }

    /**
    * @Description: 修改数据，哪个属性不为空就修改哪个属性
    * @Param: [article]
    * @return: boolean
    * @Author: zhimingw
    * @Date: 2021/5/31
    */
    @Override
    public boolean update(Article article) {
        if(articleMapper.update(article)==1){
            return true;
        }
        return false;
    }

    /**
    * @Description: 根据条件获取文章数量
    * @Param: [status]
    * @return: java.lang.Integer
    * @Author: zhimingw
    * @Date: 2021/5/31
    */
    @Override
    public Integer totalCount(Integer status) {
        return articleMapper.totalCount(status);
    }

    /**
    * @Description: 获取阅读量最高的文章
    * @Param: []
    * @return: java.util.List<top.zhimingw.pojo.Article>
    * @Author: zhimingw
    * @Date: 2021/6/1
    */
    @Override
    public List<Article> orderByReadCount() {
        List<Article> famousArticles = null;
        if(redisService.exists(ArticleKey.getfamousArticles,"")){
            famousArticles = redisService.getList(ArticleKey.getfamousArticles,"",Article.class);
        }else{
            PageHelper.startPage(1,10);
            famousArticles = getArticles(articleMapper.orderByReadCount());
            //放入缓存
            redisService.setList(ArticleKey.getfamousArticles,"",famousArticles);
        }
        return famousArticles;
    }

    /**
    * @Description: 根据发表时间降序获取文章
    * @Param: []
    * @return: java.util.List<top.zhimingw.pojo.ArticleDateArchive>
    * @Author: zhimingw
    * @Date: 2021/6/1
    */
    @Override
    public List<ArticleDateArchive> getArchive() {
        List<ArticleDateArchive> archives = null;
        if(redisService.exists(ArchivesKey.getIndex,"")){
            archives = redisService.getList(ArticleKey.getIndex,"",ArticleDateArchive.class);
        }else{
            archives = articleMapper.getArchive();
            redisService.setList(ArchivesKey.getIndex,"",archives);
        }
        return archives;
    }

    /**
    * @Description: 根据发表时间降序获取文章
    * @Param: [page]
    * @return: java.util.List<top.zhimingw.pojo.Article>
    * @Author: zhimingw
    * @Date: 2021/5/31
    */
    @Override
    public List<Article> orderByPublishTime(Integer page) {
        List<Article> articles = null;
        //获取redis中的文章
        if(redisService.exists(ArticleKey.getById,String.valueOf(page))){
            articles = redisService.getList(ArticleKey.getIndex,String.valueOf(page),Article.class);
        }else{
            PageHelper.startPage(page,10);
            articles = getArticles(articleMapper.orderByPublishTime());
            //存入缓存
            redisService.setList(ArticleKey.getIndex,String.valueOf(page),articles);
        }
        return articles;
    }

    /**
    * @Description: 阅读文章 ,阅读量加1
    * @Param: [id]
    * @return: void
    * @Author: zhimingw
    * @Date: 2021/6/8
    */
    @Override
    public void addReadCount(Integer id) {
        if(redisService.exists(ArticleKey.getByReadCount,String.valueOf(id))){
            //获取redis当前键值，并增加
            redisService.incr(ArticleKey.getByReadCount, String.valueOf(id));
        }else{//如果redis中没有当前键值，就设置
            Article article = articleMapper.queryById(id);
            redisService.set(ArticleKey.getByReadCount,String.valueOf(id),article.getReadCount()+1,0);
        }
    }

    /**
    * @Description: 根据Id获取阅读量
    * @Param: [id]
    * @return: java.lang.Integer
    * @Author: zhimingw
    * @Date: 2021/6/8
    */
    @Override
    public Integer getReadCount(Integer id) {
        Integer count = 0;
        if(redisService.exists(ArticleKey.getByReadCount,String.valueOf(id))){
            count = redisService.get(ArticleKey.getByReadCount, String.valueOf(id), Integer.class);
        }else{
            count = queryById(id).getReadCount();
            redisService.set(ArticleKey.getByReadCount,String.valueOf(id),count,0);
        }
        return count;
    }

    /**
    * @Description: 获取ES中文档的数量
    * @Param: []
    * @return: long
    * @Author: zhimingw
    * @Date: 2021/6/30
    */
    @Override
    public long getEsDocCount() {
        // 创建搜索请求
        SearchRequest searchRequest = new SearchRequest("zhimingw-blog");
        // 创建搜索对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 设置查询条件
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());

        searchRequest.source(searchSourceBuilder);

        // 执行搜索
        SearchResponse response = null;
        try {
            response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response.getHits().getTotalHits().value;
    }

    /**
    * @Description: 初始化ES
    * @Param: []
    * @return: void
    * @Author: zhimingw
    * @Date: 2021/7/1
    */
    @Override
    public void initEs() {
        articleRespository.deleteAll();
        List<Article> articles = articleMapper.queryByStatus(1);
        for(Article article:articles){
            article.setStatus(null);
            article.setKinds(null);
            article.setTags(null);
            article.setId(null);
            article.setRecentEdit(null);
            articleRespository.save(article);
        }
    }

    @Override
    public List<Article> searchFromEs(String content) {
        List<Article> result = new ArrayList<>();
        //创建搜索请求
        SearchRequest searchRequest = new SearchRequest("zhimingw-blog");
        //创建搜索对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //设置查询条件
        searchSourceBuilder.query(QueryBuilders.multiMatchQuery(content,"title","content","introduce"))
                .from(0)
                .size((int)getEsDocCount())
                .highlighter(new HighlightBuilder().field("*").requireFieldMatch(false).preTags("<span style='color:red;font-weight:500'>").postTags("</span>"));
        searchRequest.source(searchSourceBuilder);
        //执行搜索
        SearchResponse response = null;
        try {
            response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SearchHit[] hits = response.getHits().getHits();
        for(SearchHit hit:hits){
            Map<String, Object> map = hit.getSourceAsMap();
            Article temp = new Article();
            temp.setId((Integer) map.get("id"));
            temp.setIntroduce(map.get("introduce").toString());
//            temp.setPublishTime(new Date((Long) map.get("publish_time")));
            temp.setTitle(map.get("title").toString());
            temp.setReadCount((Integer) map.get("readCount"));
            temp.setComment((Integer) map.get("comment"));
            Map<String, HighlightField> fields = hit.getHighlightFields();
            //设置标题高亮
            if(fields.containsKey("title")){
                temp.setTitle(fields.get("title").fragments()[0].toString());
            }
            // 设置摘要高亮
            if (fields.containsKey("introduce")) {
                temp.setIntroduce(fields.get("introduce").fragments()[0].toString());
            }
            result.add(temp);
        }
        return getArticles(result);
    }

    /**
    * @Description: 根据标签ID获取已发布的文章
    * @Param: [id]
    * @return: java.util.List<top.zhimingw.pojo.Article>
    * @Author: zhimingw
    * @Date: 2021/7/1
    */
    @Override
    public List<Article> findByTagId(Integer id) {
        return getArticles(articleMapper.findByTagId(id));
    }

    /**
    * @Description: 根据文集ID获取已发布的文章
    * @Param: [id]
    * @return: java.util.List<top.zhimingw.pojo.Article>
    * @Author: zhimingw
    * @Date: 2021/7/1
    */
    @Override
    public List<Article> findByKindId(Integer id) {
        return getArticles(articleMapper.findByKindId(id));
    }

    @Override
    public List<Article> findByDate(Date date) {
        return getArticles(articleMapper.findByDate(date));
    }

    /**
    * @Description: 根据Id获得文章标题
    * @Param: [aId]
    * @return: java.lang.String
    * @Author: zhimingw
    * @Date: 2021/7/7
    */
    @Override
    public String getTitle(Integer aId) {
        return articleMapper.getTitle(aId);
    }

    
    /**
    * @Description: 根据状态获取文章
    * @Param: [status]
    * @return: java.util.List<top.zhimingw.pojo.Article>
    * @Author: zhimingw
    * @Date: 2021/7/11
    */
    @Override
    public List<Article> queryByStatus(Integer status) {
        List<Article> articles = articleMapper.queryByStatus(status);
        articles.forEach(article->{
            Kind kind = articleKindMapper.queryByArticleId(article.getId());
            List<Tag> tags = articleTagMapper.queryByArticleId(article.getId());
            article.setKinds(kind);
            article.setTags(tags);
        });
        return articles;
    }

    /**
    * @Description: 清空回收站
    * @Param: []
    * @return: java.lang.Integer
    * @Author: zhimingw
    * @Date: 2021/7/21
    */
    @Override
    public Integer deleteTrash() {
        return articleMapper.deleteTrash();
    }

    /**
    * @Description: 发布文章以及保存到草稿箱
    * @Param: [title, content, tags, kind, introduce, status]
    * @return: java.lang.Integer
    * @Author: zhimingw
    * @Date: 2021/7/21
    */
    @Override
    public Integer publish(String title, String content, String tags, String kind, String introduce, Integer status) {
        Article article = new Article();
        article.setTitle(title);
        article.setContent(content);
        article.setStatus(status);
        article.setComment(0);
        article.setImg(ImageUtils.getRandomFace());
        if (status != 0) {
            article.setPublishTime(new Date());
        }
        article.setRecentEdit(new Date());
        article.setReadCount(0);
        if ("".equals(introduce)) {
            // 摘要为空
            introduce = content.length() > 100 ? content.substring(0, 100) : content;
        }
        article.setIntroduce(introduce);
        if(articleMapper.insert(article)==1){
            // 处理输入的标签集合和文集
            dealTagsAndKind(article,tags,kind);
            return article.getId();
        }else{
            return 0;
        }
    }

    /**
    * @Description: 更新文章
    * @Param: [id, title, content, tags, kind, introduce, status]
    * @return: boolean
    * @Author: zhimingw
    * @Date: 2021/7/21
    */
    @Override
    public boolean update(Integer id, String title, String content, String tags, String kind, String introduce, Integer status) {
        // 首先获取文章
        Article article = articleMapper.queryById(id);
        article.setTitle(title);
        article.setContent(content);
        if("".equals(introduce)){
            //摘要为空  摘要会在文章外进行显示，帮助读者快速了解内容，如不填写则默认抓取正文前54字
            String s = content.replaceAll(" ", "");
            s = s.replaceAll("#",""); //使用replacement替换字符串中符合的regex
            s = s.replaceAll("\n","");
            if(s.length()>100){
                introduce = s.substring(0,100);
            }
        }
        article.setIntroduce(introduce);
        article.setStatus(status);
        //如果原来的发布时间为空
        if(ObjectUtils.isEmpty(article.getPublishTime())){
            article.setPublishTime(new Date());
        }
        //更新文章
        if(articleMapper.update(article)==1){
            articleTagMapper.deleteById(id);
            //处理输入的标签集合和文集
            dealTagsAndKind(article,tags,kind);
            return true;
        }else {
            return false;
        }
    }

    /**
    * @Description: 处理文章集合
    * @Param: [articles]
    * @return: java.util.List<top.zhimingw.pojo.Article>
    * @Author: zhimingw
    * @Date: 2021/6/30
    */
    private List<Article> getArticles(List<Article> articles) {
        articles.forEach(article -> {
            List<Tag> list = articleTagMapper.queryByArticleId(article.getId());
            article.setTags(list);
            // 获取该文章的分类
            Kind kinds = articleKindMapper.queryByArticleId(article.getId());
            article.setKinds(kinds);
        });
        return articles;
    }

    /**
    * @Description: 处理标签
    * @Param: [tags]
    * @return: java.util.List<top.zhimingw.pojo.Tag>
    * @Author: zhimingw
    * @Date: 2021/7/21
    */
    public List<Tag> dealTag(String tags) {
        String[] strings = tags.split(";");
        List<Tag> list = new ArrayList<>();
        for(String s : strings){
            if(!"".equals(s)){
                list.add(new Tag(s));
            }
        }
        return list;
    }

    /**
    * @Description: 处理输入的标签集合和文集
    * @Param: [article, tags, kind]
    * @return: void
    * @Author: zhimingw
    * @Date: 2021/7/22
    */
    public void dealTagsAndKind(Article article,String tags,String kind){
        // 处理输入的标签集合
        if (!"".equals(tags)) {
            List<Tag> tagList = dealTag(tags);
            tagList.forEach(tag -> {
                List<Tag> list = tagMapper.queryAll(tag);
                if (list.size() == 0) {
                    // 标签不存在,先添加标签在添加关联
                    tag.setImg(ImageUtils.getRandomFace());
                    tagMapper.insert(tag);
                    articleTagMapper.insert(new ArticleTag(article.getId(), tag.getId()));
                } else {
                    // 标签已存在则添加数据到关联表
                    articleTagMapper.insert(new ArticleTag(article.getId(), list.get(0).getId()));
                }
            });
        }
        // 处理获取到的文集
        articleKindMapper.deleteById(article.getId());
        if (!"".equals(kind)) {
            List<Kind> kinds = kindMapper.queryAll(new Kind(kind));
            articleKindMapper.insert(new ArticleKind(article.getId(), kinds.get(0).getId()));
        }
    }
}
